﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Kooboo.HtmlFunc;
using Kooboo.HtmlFunc.Providers;
using Kooboo.CMS.SiteConverter.Models;

namespace Kooboo.CMS.SiteConverter.Parser.Razor
{
    public class ListParser : ParserBase, IParser<IList>
    {
        public static Kooboo.CMS.Content.Models.Schema FillSchemas(ParserContext context, string folderName, IList<IDataItem> dataItems)
        {
            var allSchemas = context.Items[ParserUtility.AllSchemasKey] as IList<Kooboo.CMS.Content.Models.Schema>;
            var schema = allSchemas.Where(o => o.Name.IgnoreCaseEquals(folderName)).FirstOrDefault();
            if (schema == null)
            {
                schema = new Kooboo.CMS.Content.Models.Schema();
                schema.Name = folderName;
                allSchemas.Add(schema);
            }

            foreach (var field in dataItems)
            {
                var column = schema.Columns.Where(o => o.Name.IgnoreCaseEquals(field.ColumnName)).FirstOrDefault();
                if (column == null)
                {
                    column = new Kooboo.CMS.Content.Models.Column();
                    column.Name = field.ColumnName;
                    schema.Columns.Add(column);
                }

                if (string.IsNullOrWhiteSpace(column.Label))
                    column.Label = field.ColumnName;

                if (string.IsNullOrWhiteSpace(column.ControlType))
                    column.ControlType = GenerateControlType(field.ControlType);

                if (!column.ShowInGrid)
                    column.ShowInGrid = field.ShowInGrid.HasValue ? field.ShowInGrid.Value : false;

                if (string.IsNullOrWhiteSpace(column.DefaultValue))
                    column.DefaultValue = NodeExtension.GetInnerContent(field.StartNode, field.EndNode);

                if (column.Order == 0)
                    column.Order = field.Order.HasValue ? field.Order.Value : 0;

                column.DataType = GenerateDataType(field.ControlType);
            }

            // ret
            return schema;
        }

        private static Kooboo.CMS.Common.DataType GenerateDataType(string typeString)
        {
            if (string.IsNullOrWhiteSpace(typeString))
                return Kooboo.CMS.Common.DataType.String;

            switch (typeString.ToLower())
            {
                case Kooboo.HtmlFunc.AnalysisSetting.ControlType_Date:
                    return Kooboo.CMS.Common.DataType.DateTime;

                case Kooboo.HtmlFunc.AnalysisSetting.ControlType_Image:
                case Kooboo.HtmlFunc.AnalysisSetting.ControlType_Textbox:
                case Kooboo.HtmlFunc.AnalysisSetting.ControlType_Textarea:
                case Kooboo.HtmlFunc.AnalysisSetting.ControlType_Richtext:
                    return Kooboo.CMS.Common.DataType.String;

                default:
                    break;
            }

            return Kooboo.CMS.Common.DataType.String;
        }

        private static string GenerateControlType(string typeString)
        {
            if (string.IsNullOrWhiteSpace(typeString))
                return ParserSetting.DefaultControlType;

            switch (typeString.ToLower())
            {
                case Kooboo.HtmlFunc.AnalysisSetting.ControlType_Date:
                    return ParserSetting.ControlType_Date;

                case Kooboo.HtmlFunc.AnalysisSetting.ControlType_Image:
                    return ParserSetting.ControlType_File;

                case Kooboo.HtmlFunc.AnalysisSetting.ControlType_Textbox:
                    return ParserSetting.ControlType_Textbox;

                case Kooboo.HtmlFunc.AnalysisSetting.ControlType_Textarea:
                    return ParserSetting.ControlType_Textarea;

                case Kooboo.HtmlFunc.AnalysisSetting.ControlType_Richtext:
                    return ParserSetting.ControlType_Tinymce;

                default:
                    break;
            }

            return typeString;
        }

        public static void FillResult(ParserContext context, IList obj, string engineName,
            string loopStartFormat, string loopEndFormat, string blockFormat, string fieldFormat, string linkFormat, string imageSrcFormat, string pagerFormat)
        {
            if (obj.StartNode == null) { return; }
            if (obj.ItemStartNode == null) { return; }

            var schema = FillSchemas(context, obj.FolderName, obj.DataItems);

            NodeExtension.RemoveItemSiblings(obj);

            // dataRule
            var folderName = schema.Name;
            var takeTop = obj.TakeTop.HasValue ? obj.TakeTop.Value : ParserSetting.DefaultTakeTop;
            var pageSize = obj.PageSize.HasValue ? obj.PageSize.Value : ParserSetting.DefaultPageSize;
            var dataRule = new Kooboo.CMS.Sites.DataRule.FolderDataRule();
            dataRule.FolderName = folderName;
            dataRule.CategoryFolderName = string.Empty;
            dataRule.Top = takeTop.ToString();
            dataRule.PageSize = pageSize.ToString();
            dataRule.PageIndex = (takeTop > pageSize) ? "{PageIndex}" : string.Empty;
            if (!string.IsNullOrEmpty(obj.OrderBy))
            {
                dataRule.SortField = obj.OrderBy;
                dataRule.SortDirection = Kooboo.CMS.Sites.DataRule.SortDirection.Ascending;
            }
            else if (!string.IsNullOrEmpty(obj.OrderByDescending))
            {
                dataRule.SortField = obj.OrderByDescending;
                dataRule.SortDirection = Kooboo.CMS.Sites.DataRule.SortDirection.Descending;
            }

            // dataRuleSetting
            var dataName = schema.Name;
            var dataRuleSetting = new Kooboo.CMS.Sites.Models.DataRuleSetting();
            dataRuleSetting.DataRule = dataRule;
            dataRuleSetting.DataName = dataName;
            dataRuleSetting.TakeOperation = Kooboo.CMS.Sites.Models.TakeOperation.List;

            // do replace
            foreach (var field in obj.DataItems)
            {
                // query the stored column name, or there are some upper-lower-case problems
                var column = schema.Columns.Where(o => o.Name.IgnoreCaseEquals(field.ColumnName)).First();
                if (!string.IsNullOrEmpty(field.ControlType) &&
                    field.ControlType.IgnoreCaseEquals(Kooboo.HtmlFunc.AnalysisSetting.ControlType_Image))
                {
                    var img = field.StartNode.NextElement();
                    var src = img.Attr("src");
                    if (!string.IsNullOrEmpty(src))
                    {
                        column.DefaultValue = src;
                        img.Attr("src", string.Format(imageSrcFormat, column.Name));
                    }
                }
                else
                {
                    var inner = string.Format(fieldFormat, column.Name/*field.ColumnName*/);
                    NodeExtension.ReplaceInner(field.StartNode, field.EndNode, inner);
                }
            }
            foreach (var link in obj.LinkItems)
            {
                var element = link.StartNode.NextSibling;
                while (element != null && element != link.EndNode && !element.Is("A"))
                    element = element.NextSibling;

                if (element != null && element.Is("A"))
                {
                    // find the first detail page that have a detailView and has a same folderName
                    var cachedAnalyseResults = context.Items[ParserUtility.CachedAnalyseResultsKey] as List<IAnalyseResult>;
                    foreach (var analyseResult in cachedAnalyseResults)
                    {
                        var detail = analyseResult.Details.Where(o => o.FolderName.IgnoreCaseEquals(obj.FolderName)).FirstOrDefault();
                        if (detail != null)
                        {
                            var names = new List<string>();
                            var pageSetting = analyseResult.PageSetting;
                            while (pageSetting != null)
                            {
                                names.Insert(0, pageSetting.Name);
                                if (string.IsNullOrEmpty(pageSetting.Parent)) { break; }
                                pageSetting = cachedAnalyseResults.Where(o => o.PageSetting.Name.IgnoreCaseEquals(pageSetting.Parent)).Select(o => o.PageSetting).FirstOrDefault();
                            }
                            var pagePath = string.Join("/", names);
                            element.Attr("href", string.Format(linkFormat, pagePath));
                            break;
                        }
                    }
                }
            }

            var loopStartNode = NodeExtension.CreateNode(string.Format(loopStartFormat, dataRuleSetting.DataName));
            obj.ItemStartNode.ParentNode.InsertBefore(loopStartNode, obj.ItemStartNode);

            var loopEndNode = NodeExtension.CreateNode(loopEndFormat);
            obj.ItemEndNode.ParentNode.InsertAfter(loopEndNode, obj.ItemEndNode);

            if (!string.IsNullOrEmpty(dataRule.PageIndex))
            {
                var pagerNode = NodeExtension.CreateNode(string.Format(pagerFormat, dataRuleSetting.DataName));
                obj.ItemEndNode.ParentNode.InsertAfter(pagerNode, loopEndNode);
            }

            IReplacement replacement = null;
            if (obj.EditableAttribute != null)
            {
                var attrName = ("attr" + Guid.NewGuid().ToString().Replace("-", string.Empty)).ToLower();
                obj.EditableAttribute.OwnerNode.Attr(attrName, blockFormat);
                replacement = new Replacement()
                {
                    From = attrName + "=\"" + blockFormat + "\"",
                    To = blockFormat
                };
            }

            // remove func markers
            if (ParserSetting.RemoveFuncMarkers)
            {
                foreach (var item in obj.DataItems)
                {
                    item.EndNode.RemoveWithPrevWhitespace();
                    item.StartNode.ParentNode.RemoveChild(item.StartNode);
                }
                foreach (var item in obj.LinkItems)
                {
                    item.EndNode.RemoveWithPrevWhitespace();
                    item.StartNode.RemoveWithPrevWhitespace();
                }
                if (obj.ItemStartNode != null)
                {
                    obj.ItemEndNode.RemoveWithPrevWhitespace();
                    obj.ItemStartNode.RemoveWithPrevWhitespace();
                }
                if (obj.EditableAttribute != null)
                {
                    obj.EditableAttribute.Remove();
                }
            }

            // fill view
            ViewPartParser.FillResult(context, obj, engineName, replacement, dataRuleSetting);
        }

        #region IParser<IList> Members

        public void Parse(IList obj)
        {
            var loopStartFormat = @"
@foreach (var item in ViewBag.{0})
{{
";
            var blockFormat = @"@ViewHelper.Edit(item)";
            var fieldFormat = @"@ViewHelper.EditField(item, ""{0}"")"; //var fieldFormat = @"@Html.Raw(item.{0})";
            var linkFormat = @"@Url.FrontUrl().PageUrl(""{0}"", new {{ UserKey = item.UserKey }})";
            var imageSrcFormat = @"@Url.Content(item.{0})";
            var loopEndFormat = @"
}";
            var pagerFormat = @"
<div class=""pager"">
    @Html.FrontHtml().Pager(ViewBag.{0})
</div>";

            FillResult(this.Context, obj, this.EngineName, loopStartFormat, loopEndFormat, blockFormat, fieldFormat, linkFormat, imageSrcFormat, pagerFormat);
        }

        #endregion
    }
}
